#include "game_entity.h"
#include "game.h"
#include "game_render_group.h"
#include "game_debug.h"

internal void MoveEntity(game_state *GameState, sim_region *SimRegion, entity *Entity, real32 dt,
                         move_spec *MoveSpec, v2 ddP);

// 返回一个默认的 move_spec 对象，包含默认的物理属性
move_spec DefaultMoveSpec() {
    move_spec Result;  // 创建一个 move_spec 类型的变量 Result，用于存储默认的运动参数
    // 默认值设置
    Result.UnitMaxAccelVector = false;  // 默认不使用最大加速度向量（不启用最大加速度）
    Result.Speed = 1.0f;                // 默认速度为 1.0（物体的初始速度）
    Result.Drag = 0.0f;                 // 默认阻力系数为 0.0（表示没有阻力）
    return Result;                      // 返回配置好的默认 move_spec 对象
}

void UpdateMonster(sim_region *SimRegion, entity *Entity, real32 dt) {
    (void)SimRegion;
    (void)Entity;
    (void)dt;
}

void MakeEntitySpecial(entity *Entity, v3 P, v3 dP) {
    Entity->P = P;    // 设置实体位置
    Entity->dP = dP;  // 设置实体的速度
}

int32 ConvertToLayerRelative(game_mode_world *WorldMode, real32 *Z) {
    int32 RelativeIndex = 0;
    RecanonicalizeCoord(WorldMode->TypicalFloorHeight, &RelativeIndex, Z);
    return RelativeIndex;
}

void UpdateAndRenderEntities(game_mode_world *WorldMode, sim_region *SimRegion,
                             render_group *RenderGroup, v3 CameraP, loaded_bitmap *DrawBuffer,
                             v4 BackgroundColor, real32 dt, transient_state *TranState,
                             v2 MouseP) {  //
    (void)DrawBuffer;
    TIMED_FUNCTION();
    (void)BackgroundColor;
    real32 FadeTopStartZ = 0.5f * WorldMode->TypicalFloorHeight;
    real32 FadeTopEndZ = 1.0f * WorldMode->TypicalFloorHeight;
    real32 FadeBottomStartZ = -1.0f * WorldMode->TypicalFloorHeight;
    real32 FadeBottomEndZ = -4.0f * WorldMode->TypicalFloorHeight;

#define MinimumLevelIndex -4
#define MaximumLevelIndex 1
    real32 FogAmount[(MaximumLevelIndex - MinimumLevelIndex + 1)] = {};
    real32 TestAlpha = 0;
    for (uint32 LevelIndex = 0; LevelIndex < ArrayCount(FogAmount); ++LevelIndex) {
        // 获取实体的地面位置，并与相机位置 (CameraP) 进行差值计算，得到相对相机的地面位置
        // v3 CameraRelativeGroundP = GetEntityGroundPoint(Entity) - CameraP;
        int32 RelativeLayerIndex = MinimumLevelIndex + LevelIndex;
        real32 CameraRelativeGroundZ =
            RelativeLayerIndex * WorldMode->TypicalFloorHeight - WorldMode->CameraOffset.z;
        TestAlpha = ClampMapToRange(FadeTopEndZ, CameraRelativeGroundZ, FadeTopStartZ);
        FogAmount[LevelIndex] =
            ClampMapToRange(FadeBottomStartZ, CameraRelativeGroundZ, FadeBottomEndZ);
    }
    int32 StopLevelIndex = MaximumLevelIndex - 1;
    uint32 AlphaFloorRenderTarget = 1;
    uint32 NormalFloorClipRect = RenderGroup->CurrentClipRectIndex;
    uint32 AlphaFloorClipRect = RenderGroup->CurrentClipRectIndex;
    if (TestAlpha > 0) {
        StopLevelIndex = MaximumLevelIndex;
        AlphaFloorClipRect = PushClipRect(RenderGroup, 0, 0, DrawBuffer->Width, DrawBuffer->Height,
                                          AlphaFloorRenderTarget);
    }
    int32 CurrentAbsoluteZLayer = (SimRegion->EntityCount ? SimRegion->Entities[0].ZLayer : 0);
    // 添加背景填充颜色
    // 在整个缓冲区内绘制一个矩形，作为游戏的背景。
    // 这里的颜色是深红色（0.3f, 0.0f, 0.1f）。
    v2 vBufferMin = {0.0f, 0.0f};
    (void)vBufferMin;
    // v2 vBufferWidthHeight = {(real32)Buffer->Width, (real32)Buffer->Height};

    // DrawRectangle(DrawBuffer, vBufferMin, vBufferWidthHeight, 0.3f, 0.0f, 0.1f);

    // 将位图数据从 `WorldMode->PixelPointer` 复制到缓冲区中
    // 定义图像的像素宽度和高度
    // loaded_bitmap Backdrop = *GetBitmap(&WorldMode->Assets, GAI_Backdrop);
    for (uint32 EntityIndex = 0; EntityIndex < SimRegion->EntityCount; EntityIndex++) {
        entity *Entity = SimRegion->Entities + EntityIndex;
        debug_id EntityDebugID = DEBUG_POINTER_ID((void *)(uint64)Entity->ID.Value);
        if (DEBUG_REQUESTED(EntityDebugID)) {
            DEBUG_BEGIN_DATA_BLOCK("Simulation/Entity");
        }
        // 检查实体是否可以更新
        // 'Updatable' 标志表示实体是否应该被更新。
        // 如果实体的 'Updatable' 标志为真，表示实体处于有效的更新区域内，
        // 可以执行更新操作。如果为假，则跳过该实体，不进行更新。
        if (Entity->Flags & EntityFlag_Active) {
            // 在这里执行实体的更新逻辑
            // 获取当前实体的高频、低频和低频实体信息

            // 遍历游戏状态中的所有实体，EntityIndex 是当前实体的索引，Entity 是当前实体的指针。

            //  跳跃功能测试
            //  更新高实体的位置信息（可能是玩家或其他重要实体）
            //  EntityOffsetForFrame 是本帧的位移增量，更新实体的位置

            // 获取当前帧的时间步长（dt），用于计算物理更新
            // 计算影像透明度，基于实体与地面间的相对高度差
            /*
            计算影像透明度（ShadowAlpha）时，透明度基于实体与地面之间的相对高度差。
            Entity->P.z 是实体的位置的 Z 值，即实体底部所在的高度。
            Entity->Dim.z 是实体的高度，表示实体从地面到顶部的距离。
            通过减去实体的高度，得到实体底部离地面的实际高度差。
            然后，将该差值乘以 0.5f，并从 1.0f
            中减去，得到影像的透明度。这个公式的目的是随着实体距离地面越远，影像的透明度逐渐减少。
            */
            real32 ShadowAlpha = 1.0f - 0.5f * Entity->P.z;

            // 如果计算后的透明度小于0，则将其设置为0
            if (ShadowAlpha < 0) {
                ShadowAlpha = 0.0f;
            }
            BEGIN_BLOCK("EntityPhysics");
            // hero_bitmaps *HeroBitmaps = &TranState->Assets->HeroBitmaps[Entity->FacingDirection];
            switch (Entity->MovementMode) {
                case MovementMode_Planted: {
                } break;
                case MovementMode_Hopping: {
                    v3 MovementTo = GetSimSpaceTraversable(Entity->Occupying).P;
                    v3 MovementFrom = GetSimSpaceTraversable(Entity->CameFrom).P;

                    Entity->tMovement += 4 * dt;
                    real32 tJump = 0.1f;
                    real32 tThrust = 0.2f;
                    real32 tLand = 0.8f;
                    if (Entity->tMovement < tThrust) {
                        Entity->ddtBob = 30.0f;
                    }

                    if (Entity->tMovement < tLand) {
                        real32 t = ClampMapToRange(tJump, Entity->tMovement, tLand);
                        v3 a = v3{0, -2.0f, 0};
                        v3 b = (MovementTo - MovementFrom) - a;
                        Entity->P = a * t * t + b * t + MovementFrom;
                    }
                    if (Entity->tMovement >= 1.0f) {
                        Entity->P = MovementTo;
                        Entity->CameFrom = Entity->Occupying;
                        Entity->MovementMode = MovementMode_Planted;
                        Entity->dtBob = -2.0f;
                    }
                    if (Entity->tMovement > 1.0f) {
                        Entity->tMovement = 1.0f;
                    }
                } break;
                case MovementMode_AngleAttackSwipe: {
                    if (Entity->tMovement < 1.0f) {
                        Entity->AngleCurrent =
                            Lerp(Entity->AngleStart, Entity->tMovement, Entity->AngleTarget);
                        Entity->AngleCurrentDistance =
                            Lerp(Entity->AngleBaseDistance, Triangle01(Entity->tMovement),
                                 Entity->AngleSwipDistance);

                    } else {
                        Entity->MovementMode = MovementMode_AngleOffset;
                        Entity->AngleCurrent = Entity->AngleTarget;
                        Entity->AngleCurrentDistance = Entity->AngleBaseDistance;
                    }
                    Entity->tMovement += 4.0f * dt;
                    if (Entity->tMovement > 1.0f) {
                        Entity->tMovement = 1.0f;
                    }
                }
                case MovementMode_AngleOffset: {
                    v2 Arm = Entity->AngleCurrentDistance *
                             Arm2(Entity->AngleCurrent + Entity->FacingDirection);
                    Entity->P = Entity->AngleBase + v3{Arm.x, Arm.y + 0.5f, 0.0f};
                } break;
            }
            real32 Cp = 100.0f;
            real32 Cv = 10.0f;
            Entity->ddtBob += Cp * (0.0f - Entity->tBob) + Cv * (0.0f - Entity->dtBob);
            Entity->tBob += Entity->ddtBob * dt * dt + Entity->dtBob * dt;
            Entity->dtBob += Entity->ddtBob * dt;
            if ((LengthSq(Entity->dP) > 0) || (LengthSq(Entity->ddP) > 0)) {
                MoveEntity(WorldMode, SimRegion, Entity, dt, Entity->ddP);
            }
            END_BLOCK();
            object_transform EntityTransform = DefaultUprightTransform();
            EntityTransform.OffsetP = GetEntityGroundPoint(Entity) - CameraP;
            BEGIN_BLOCK("EntityRendering");
            asset_vector MatchVector = {};
            MatchVector.E[Tag_FacingDirection] = (real32)Entity->FacingDirection;

            asset_vector WeightVector = {};
            WeightVector.E[Tag_FacingDirection] = 1.0f;
            EntityTransform.OffsetP = GetEntityGroundPoint(Entity) - CameraP;
            int32 RelativeLayer = (Entity->ZLayer - SimRegion->Origin.ChunkZ);
            EntityTransform.ManualSort.AlwaysInFrontOf = Entity->ManualSort.AlwaysInFrontOf;
            EntityTransform.ManualSort.AlwaysBehind = Entity->ManualSort.AlwaysBehind;
            EntityTransform.ChunkZ = Entity->ZLayer;
            if ((RelativeLayer >= MinimumLevelIndex) && (RelativeLayer <= StopLevelIndex)) {
                if (CurrentAbsoluteZLayer != Entity->ZLayer) {
                    Assert(CurrentAbsoluteZLayer < Entity->ZLayer);
                    CurrentAbsoluteZLayer = Entity->ZLayer;
                    PushSortBarrier(RenderGroup, false);
                }
                // real32 Alpha = TestAlpha[RelativeLayer - MinimumLevelIndex];
                int32 LayerIndex = RelativeLayer - MinimumLevelIndex;
                if (RelativeLayer == MaximumLevelIndex) {
                    RenderGroup->CurrentClipRectIndex = AlphaFloorClipRect;
                    EntityTransform.tColor = v4{0, 0, 0, 0};
                } else {
                    RenderGroup->CurrentClipRectIndex = NormalFloorClipRect;
                    EntityTransform.Color = BackgroundColor;
                    EntityTransform.tColor = FogAmount[LayerIndex] * v4{1, 1, 1, 0};
                }
                BEGIN_BLOCK("PieceRendering");
                if (Entity->PieceCount) {
                    BeginAggregateSortKey(RenderGroup);
                }
                for (uint32 PieceIndex = 0; PieceIndex < Entity->PieceCount; ++PieceIndex) {
                    entity_visible_piece *Piece = Entity->Pieces + PieceIndex;
                    bitmap_id BitmapID = GetBestMatchBitmapFrom(TranState->Assets, Piece->AssetType,
                                                                &MatchVector, &WeightVector);
                    v2 XAxis = {1, 0};
                    v2 YAxis = {0, 1};
                    if (Piece->Flags & PieceMove_AxesDeform) {
                        XAxis = Entity->XAxis;
                        YAxis = Entity->YAxis;
                    }
                    // real32 tBob = 0.0f;
                    v3 Offset = {};
                    if (Piece->Flags & PieceMove_BobOffset) {
                        // tBob = Entity->tBob;
                        Offset = ToV3(Entity->FloorDisplace, 0.0f);
                        Offset.y += Entity->tBob;
                    }
                    v4 Color = Piece->Color;
                    PushBitmap(RenderGroup, &EntityTransform, BitmapID, Piece->Height,
                               Offset + Piece->Offset, Color, 1.0f, XAxis, YAxis);
                }
                if (Entity->PieceCount) {
                    EndAggregateSortKey(RenderGroup);
                }
                END_BLOCK();
                void DrawHitpoints(entity * Entity, render_group * RenderGroup,
                                   object_transform Transform);
                DrawHitpoints(Entity, RenderGroup, EntityTransform);
                EntityTransform.Upright = false;
                BEGIN_BLOCK("VolumeRendering");
                for (uint32 VolumeIndex = 0; VolumeIndex < Entity->Collision->VolumeCount;
                     ++VolumeIndex) {
#if 0
                    entity_collision_volume *Volume = Entity->Collision->Volumes + VolumeIndex;
                    PushRectOutline(RenderGroup, EntityTransform,
                                    Volume->OffsetP - V3(0.0f, 0.0f, 0.5f * Volume->Dim.z),
                                    Volume->Dim.xy, V4(0, 0.5f, 1.0f, 1.0f));
#endif
                }
                END_BLOCK();
                BEGIN_BLOCK("TraversableRendering");
                for (uint32 TraversableIndex = 0; TraversableIndex < Entity->TraversableCount;
                     ++TraversableIndex) {
                    entity_traversable_point *Traversable = Entity->Traversables + TraversableIndex;
                    PushRect(RenderGroup, &EntityTransform, Traversable->P, V2(1.4f, 1.4f),
                             Traversable->Occupier ? V4(1.0, 0.0f, 0.0f, 1.0f)
                                                   : V4(0.05f, 0.25f, 0.05f, 1.0f));
#if 0
                    PushRectOutline(RenderGroup, EntityTransform, Traversable->P, v2{1.2f, 1.2f},
                                v4{0, 0, 0, 1});
#endif
                }
                END_BLOCK();
                if (Global_Entities_DrawEntityOutline) {
#if 0

RenderGroup->Transform.OffsetP = v3{0, 0, 0};
RenderGroup->Transform.Scale = 1.0f;
v4 OutlineColor = v4{1, 0, 1, 1};
// v2 MetersMouseP = MouseP * (1.0f / RenderGroup->Transform.MetersToPixels);
real32 LocalZ = 3.0f;
v3 WorldMouseP = Unproject(RenderGroup, MouseP, LocalZ);
RenderGroup->Transform.OffsetP = WorldMouseP;
PushRect(RenderGroup, v3{0, 0, 0}, v2{1.0f, 1.0f}, v4{0, 0, 1, 1});
#endif
#if 1

#endif
                }
                RenderGroup->DebugTag = 0;
                if (DEBUG_UI_ENABLED) {
                    v4 OutlineColor = {};
                    for (uint32 VolumeIndex = 0; VolumeIndex < Entity->Collision->VolumeCount;
                         ++VolumeIndex) {
                        // 获取当前体积
                        entity_collision_volume *Volume = Entity->Collision->Volumes + VolumeIndex;
                        // 遍历空间实体的所有碰撞体积
                        v3 LocalMouseP = Unproject(RenderGroup, &EntityTransform,
                                                   MouseP);  //, Volume->OffsetP.z);
#if 0
PushRect(RenderGroup, ToV3(LocalMouseP.xy, 0.0f), v2{1.0f, 1.0f}, v4{0, 0, 1, 1});
#endif
                        if ((LocalMouseP.x > -0.5f * Volume->Dim.x) &&
                            (LocalMouseP.x < 0.5f * Volume->Dim.x) &&
                            (LocalMouseP.y > -0.5f * Volume->Dim.y) &&
                            (LocalMouseP.y < 0.5f * Volume->Dim.y)) {
                            DEBUG_HIT(EntityDebugID, LocalMouseP.z);
                        }
                        if (DEBUG_HIGHLIGHTED(EntityDebugID, &OutlineColor)) {
                            PushRectOutline(RenderGroup, &EntityTransform,
                                            Volume->OffsetP - V3(0, 0, 0.5f * Volume->Dim.z),
                                            Volume->Dim.xy, OutlineColor, 0.05f);
                        }
                    }
                }

                if (DEBUG_REQUESTED(EntityDebugID)) {
                    DEBUG_VALUE(Entity->ID.Value);
                    DEBUG_VALUE(Entity->P);
                    DEBUG_VALUE(Entity->dP);
                    DEBUG_VALUE(Entity->DistanceLimit);
                    DEBUG_VALUE(Entity->FacingDirection);
                    DEBUG_VALUE(Entity->tBob);
                    DEBUG_VALUE(Entity->HitPointMax);
                    // DEBUG_VALUE(HeroBitmaps.Torso);
                    DEBUG_BEGIN_ARRAY(Entity->HitPoint);
#if 0
for (uint32 HitPointIndex = 0; HitPointIndex < Entity->HitPointMax;
++HitPointIndex) {

DEBUG_VALUE(Entity->HitPoint[HitPointIndex]);
}
#endif
                    DEBUG_END_ARRAY();
#if 0
DEBUG_VALUE(Entity->HitPoint);
DEBUG_VALUE(Entity->Sword);
#endif
                    DEBUG_VALUE(Entity->WalkableDim);
                    DEBUG_VALUE(Entity->WalkableHeight);
                    DEBUG_END_DATA_BLOCK("Simulation/Entity");
                }
            }
            END_BLOCK();
        }
    }
    RenderGroup->CurrentClipRectIndex = NormalFloorClipRect;
    if (TestAlpha > 0) {
        PushBlendRenderTarget(RenderGroup, TestAlpha, AlphaFloorRenderTarget);
    }
}